.Dd September 21, 2025
.Dt R_MAGIC 3
.Os
.Sh NAME
.Nm r_magic
.Nd File type detection library using magic numbers
.Sh SYNOPSIS
.In r_magic.h
.Pp
.Sh DESCRIPTION
The
.Nm r_magic
library provides file type detection using magic number patterns.
It can identify file types by examining the content of files or buffers,
similar to the Unix
.Xr file 1
command.
.Pp
The library uses a database of magic patterns that describe how to
recognize different file formats based on their binary signatures,
text patterns, and structural characteristics.
.Sh INITIALIZATION
A magic context holds the parsed magic database and runtime state; allocate one
before attempting to probe files or buffers and free it when finished.
.Bd -literal -offset indent
/* allocate and free a magic context */
RMagic *r_magic_new(int flags);
void r_magic_free(RMagic *ms);

/* example */
RMagic *magic = r_magic_new(R_MAGIC_NONE);
if (!magic) { /* handle allocation error */ }
.Ed
.Pp
After creating the instance you must load a magic database (or a buffer
containing a magic database) before asking it to identify content.
.Bd -literal -offset indent
/* load default database */
bool r_magic_load(RMagic *ms, const char *magicfile);
bool r_magic_load_buffer(RMagic *ms, const ut8 *buf, size_t len);
.Ed
.Sh FILE TYPE DETECTION
Once a magic instance is loaded it can inspect files, file descriptors or
in-memory buffers. The functions return a pointer to an internal, NUL-terminated
string describing the matching type (do not free it). If no match is found
they return NULL and you may call
.Fn r_magic_error
to obtain diagnostics.
.Bd -literal -offset indent
/* signatures */
const char *r_magic_file(RMagic *ms, const char *path);
const char *r_magic_descriptor(RMagic *ms, int fd);
const char *r_magic_buffer(RMagic *ms, const void *buf, size_t nb);
.Ed
.Pp
Use the buffer API when the data is already in memory (for example a block
read from a file or a memory map). `libr/core` uses this approach when
detecting the type of the current block being inspected (see
`libr/core/cmd_magic.inc.c`), then combines the returned description with
further actions (flags, printing or nested probes using offsets).
.Bd -literal -offset indent
/* example: probe a memory buffer */
const char *type = r_magic_buffer(magic, data, data_len);
if (type) {
    printf("Buffer type: %s\n", type);
} else {
    const char *err = r_magic_error(magic);
    fprintf(stderr, "magic failed: %s\n", err ? err : "unknown");
}
.Ed
.Sh CONFIGURATION FLAGS
Flags control how the magic engine behaves (what it searches for and the
format of the output). Set flags when creating the instance or at runtime
with
.Fn r_magic_setflags :
.Bd -literal -offset indent
void r_magic_setflags(RMagic *ms, int flags);
.Ed
.Pp
Common flags include MIME-only output or enabling debug diagnostics; many
others tune which checks are performed (compressed files, ELF details, etc.).
.Bl -tag -width "R_MAGIC_MIME_ENCODING"
.It Dv R_MAGIC_NONE
No special flags
.It Dv R_MAGIC_DEBUG
Enable debugging output
.It Dv R_MAGIC_MIME_TYPE
Return only MIME type
.It Dv R_MAGIC_MIME_ENCODING
Return only MIME encoding
.It Dv R_MAGIC_CONTINUE
Return all matches, not just first
.It Dv R_MAGIC_RAW
Do not translate unprintable characters
.El
.Sh ERROR HANDLING
The magic API reports human-readable error messages and an errno-like value
when operations fail (for example, inability to open the magic file or parse
its contents). Query these functions after an operation returns NULL/false.
.Bd -literal -offset indent
const char *r_magic_error(RMagic *ms);
int r_magic_errno(RMagic *ms);
.Ed
.Pp
Callers should always check the return value of load/probe functions and
then inspect `r_magic_error` for diagnostics. In long-running programs keep
the magic instance around and reload only when the database changes (this is
the pattern used in `libr/core`).
.Sh DATABASE MANAGEMENT
The magic database can be loaded from the system default path, from a
specific file, or from a buffer in memory. Helper functions also allow
compiling and syntax-checking magic files.
.Bd -literal -offset indent
/* signatures */
bool r_magic_load(RMagic *ms, const char *magicfile);
bool r_magic_load_buffer(RMagic *ms, const ut8 *buf, size_t len);
bool r_magic_compile(RMagic *ms, const char *magicfile);
bool r_magic_check(RMagic *ms, const char *magicfile);
.Ed
.Pp
In practice `libr/core` will call `r_magic_load` once (using the `dir.magic`
configuration key) and reuse the returned context for multiple buffer probes.
If you wish to supply a custom database at runtime use
`r_magic_load_buffer` or `r_magic_compile` to validate a file first.
.Bd -literal -offset indent
/* example: load custom magic then probe a buffer */
if (!r_magic_load(magic, "/usr/share/magic/magic.mgc")) {
    fprintf(stderr, "failed to load magic: %s\n", r_magic_error(magic));
}
const char *t = r_magic_buffer(magic, data, data_len);
.Ed
.Sh SUPPORTED FORMATS
The library can detect hundreds of file formats including:
.Bl -bullet
.It
Executable formats (ELF, PE, Mach-O)
.It
Archives (ZIP, TAR, RAR)
.It
Images (JPEG, PNG, GIF, BMP)
.It
Documents (PDF, DOC, XLS)
.It
Audio/Video (MP3, MP4, AVI)
.It
Compressed files (GZ, BZ2, XZ)
.It
And many others
.El
The following examples demonstrate common, practical usages of the API.
.Pp
1) Simple command-line file probe — same pattern used by `rabin2` and the
   `cmd.magic` implementation in `libr/core`.
.Bd -literal -offset indent
#include <r_magic.h>
#include <stdio.h>

int main(int argc, char **argv) {
    if (argc < 2) { return 1; }
    RMagic *m = r_magic_new(R_MAGIC_NONE);
    if (!m) { perror("r_magic_new"); return 1; }
    if (!r_magic_load(m, NULL)) {
        fprintf(stderr, "load failed: %s\n", r_magic_error(m));
        r_magic_free(m);
        return 1;
    }
    const char *t = r_magic_file(m, argv[1]);
    if (t) printf("%s: %s\n", argv[1], t);
    r_magic_free(m);
    return 0;
}
.Ed
.Pp
2) Inspecting an in-memory block and reacting to generic "data" results.
   `libr/core` probes the current block and, when the result is generic
   (for example "data"), it may choose to continue searching at a different
   alignment or attempt more specific heuristics.
.Bd -literal -offset indent
RMagic *m = r_magic_new(0);
r_magic_load(m, NULL);
const char *info = r_magic_buffer(m, block, block_len);
if (info) {
    if (!strcmp(info, "data")) {
        /* fallback: try different alignments or other detectors */
    } else {
        printf("info: %s\n", info);
    }
}
r_magic_free(m);
.Ed
.Pp
3) Request MIME-only output — useful when integrating magic into
   automated pipelines.
.Bd -literal -offset indent
r_magic_setflags(m, R_MAGIC_MIME_TYPE);
const char *mime = r_magic_buffer(m, data, size);
printf("MIME: %s\n", mime ? mime : "unknown");
.Ed
.Sh SEE ALSO
.Xr r_bin 3 ,
.Xr r_util 3
